package by.bsuir.util;

import java.io.*;
import java.net.*;
import java.util.*;

import by.bsuir.entity.Node;

/**
 * @author Raman_Pliashkou
 */
public class InetScan {

    private Node rootNode = new Node();

    private AuthListFiles auth = null;

    private final List<InetAddress> addresses = new ArrayList<InetAddress>();

    private final List<String> hosts = new ArrayList<String>();

    /**
     * @return the rootNode
     */
    public Node getRootNode() {
        return rootNode;
    }

    /**
     * @param rootNode the rootNode to set
     */
    public void setRootNode(Node rootNode) {
        this.rootNode = rootNode;
    }

    /**
     * @return the auth
     */
    public AuthListFiles getAuth() {
        return auth;
    }

    /**
     * @return the addresses
     */
    public List<InetAddress> getAddresses() {
        return addresses;
    }

    /**
     * @return the hosts
     */
    public List<String> getHosts() {
        return hosts;
    }

    public InetScan(String file) {
        try {
            Properties props = new Properties();
            FileInputStream in = new FileInputStream(file);
            props.load(in);
            String login = props.getProperty("access.login");
            String password = props.getProperty("access.password");
            String domain = props.getProperty("access.domain");
            auth = new AuthListFiles(login, password, domain);
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public InetScan(String login, String password, String domain) {
        try {
            auth = new AuthListFiles(login, password, domain);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    private List<String> getProcessOutput(InputStreamReader processInputStream) throws IOException {

        List<String> shares = new ArrayList<String>();
        BufferedReader br = new BufferedReader(processInputStream);

        for (int i = 0; i < 7; i++) {
            br.readLine();
        }
        try {
            while (true) {
                String temp = br.readLine();
                if (temp == null) {
                    break;
                } else if (temp.equalsIgnoreCase("")) {
                    continue;
                }

                int lastInd = temp.trim().lastIndexOf(" ");
                String s = temp.substring(0, lastInd).trim();
                shares.add(s);
            }
            if (shares.size() > 0) {
                shares.remove(shares.size() - 1);
            }
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }
        return shares;
    }

    public List<String> runCMD(String s) {
        Runtime rt = Runtime.getRuntime();
        Process process;
        try {
            process = rt.exec(s);
            return getProcessOutput(new InputStreamReader(process.getInputStream()));
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }
        return null;
    }

    public List<String> getShareList(String host) {
        List<String> shares = runCMD("net view \\\\" + host);
        return shares;
    }

    public void getInterfaces() {
        try {
            Enumeration e = NetworkInterface.getNetworkInterfaces();

            while (e.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface) e.nextElement();
                System.out.println("Net interface: " + ni.getName());

                Enumeration e2 = ni.getInetAddresses();

                while (e2.hasMoreElements()) {
                    InetAddress ip = (InetAddress) e2.nextElement();
                    System.out.println("IP address: " + ip.toString());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    InetAddress getByName(String host) throws UnknownHostException, IOException {
        InetAddress address = InetAddress.getByName(host);
        return address;
    }

    public Node scan(Long timeout, int count, int firstIp, int rightIp) throws UnknownHostException, IOException {
        rootNode = new Node();
        rootNode.setName("Network");
        rootNode.setHost("Network");
        int maxHost = 0;
        hosts.clear();
        InetAddress localhost = InetAddress.getLocalHost();
        byte[] ip = localhost.getAddress();
        for (int i = firstIp; i <= rightIp; i++) {
            if (count != 0 && maxHost == count) {
                break;
            }
            ip[3] = (byte) i;
            InetAddress address = InetAddress.getByAddress(ip);
            if (address != null) {
                if (timeout != null) {
                    if (address.isReachable(timeout.intValue())) {
                        addresses.add(address);
                        maxHost++;
                        // print(address);
                    }
                } else {
                    if (!address.getHostAddress().equals(address.getHostName())) {
                        addresses.add(address);
                        maxHost++;
                        // print(address);
                    }
                }

            }
        }
        String tab = "------- ";
        for (InetAddress address : addresses) {
            Node nodeHost = new Node();
            nodeHost.setType(true);
            nodeHost.setHost(address.getHostName());
            nodeHost.setName(address.getHostName());
            rootNode.add(nodeHost);
            hosts.add(address.getHostName());
            // rootNode.add(nodeShare);

            List<String> listShares = getShareList(address.getHostName());
            print(address);

            for (String s : listShares) {
                System.out.println(tab + s);
                try {
                    Node nodeShare = new Node();
                    System.out.println(tab);
                    nodeShare.setName(s);
                    nodeShare.setHost(nodeHost.getHost());
                    nodeShare.setType(true);
                    nodeShare.setTypeShare(true);
                    nodeHost.getNodes().add(nodeShare);
                    auth.getTree(nodeShare);
                } catch (Exception ex) {
                    System.out.println("Access denied.");
                    // ex.printStackTrace();
                }
            }
        }
        return rootNode;
    }

    public Node scan(String host) {
        rootNode = new Node();
        rootNode.setName("Network");
        rootNode.setHost("Network");
        Node nodeHost = new Node();

        try {
            InetAddress address = InetAddress.getByName(host);
            List<String> listShares = getShareList(address.getHostName());
            print(address);
            nodeHost.setType(true);
            nodeHost.setHost(address.getHostName());
            nodeHost.setName(address.getHostName());
            rootNode.add(nodeHost);
            for (String s : listShares) {
                try {
                    Node nodeShare = new Node();
                    nodeShare.setTypeShare(true);
                    nodeShare.setName(s);
                    nodeShare.setHost(nodeHost.getHost());
                    nodeShare.setType(true);
                    nodeHost.getNodes().add(nodeShare);
                    auth.getTree(nodeShare);
                } catch (Exception ex) {
                    System.out.println("Access denied.");
                    // ex.printStackTrace();
                }
            }

        } catch (UnknownHostException ex) {
            ex.printStackTrace();
        }
        return rootNode;
    }

    public static Node search(String index, Node root) {
        if (root.getChild().size() > 0) {
            Node searchNode = new Node();
            searchNode.setName("Network");
            searchNode.setHost("Network");
            List<Component> nodes = new ArrayList<Component>();
            CompositeIterator iterator = new CompositeIterator(root.createIterator());
            while (iterator.hasNext()) {
                Component component = (Component) iterator.next();
                Node nonde = (Node) component;
                if (nonde.getName() != null && nonde.getName().contains(index) && nonde.isFile()) {
                    nodes.add(nonde);
                }
            }
            searchNode.setNodes(nodes);
            return searchNode;
        }
        return null;
    }

    public void print() {
        for (InetAddress ia : addresses) {
            print(ia);
        }
    }

    public void print(InetAddress ia) {
        System.out.println("host name: " + ia.getHostName() + "; Host Address: " + ia.getHostAddress());
    }
}
